# VUE Slots

# Slots

To use a component as a wrapper (eg a Card) around content -› pass more complex data to child.

  • Allows to receive HTML-Content (with Vue-Features) from outside of the component.

  • (think: Props=data, slots=html-code)

  • The Parent provides the HTML-Code, that is inside of the slot

  • not self-closing

eg:

parent:

<div v-if="showModal">
    <Modal theme="sale" @closeModal="toggleModal">
      <h1>Headline</h1>
      <p>text</p>
    </Modal>
</div>

child: add <slot>

<div class="modal" :class="{ sale: theme === 'sale'}">
	<slot></slot>
</div>

or:

// BaseCard.vue

<template>
  <div>
    <slot></slot>
  </div>
</template>

<script>
export default {};
</script>

<style scoped>
div {
  margin: 2rem auto;
  max-width: 30rem;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
  padding: 1rem;
}
</style>
 <section>
    <BaseCard>
      <header>
        <h3>{{ fullName }}</h3>
      </header>
      <p>{{ infoText }}</p>
    </BaseCard>
  </section>

could be registered globally

Example- Modal:

<div class="backdrop" @click.self="closeModal">
    <div class="modal " :class="{ sale: theme === 'sale'}">
        <slot>Default content if no data was passed</slot>
        <div class="actions">
            <slot name="links"></slot>
        </div>
    </div>
</div>

# Named Slots

if you use more than one slot in your component, you can add names to the slot:

-> wrap in <template > and add v-slot:-directive

you don't have to name all slots, one unnamed default-slot is ok

child:

<template>
  <div>
    <header>
      <slot name="header"></slot>  
    </header>
    <slot></slot>
  </div>
</template>

parent:

<BaseCard >
	<template v-slot:header>
		<h3>{{ fullName }}</h3>
	</template>
	<p>{{ infoText }}</p>
</BaseCard >

content, that is not in the <template> will automatically go to the (unnamed) default-slot.

to make this clear, you can also use v-slot:default: (reserved name)

<BaseCard>
	<template v-slot:header>
		<h2>Available Badges</h2>
	</template>
	<template v-slot:default>
		<ul>
			<li>
				<base-badge type="admin" caption="ADMIN"></base-badge>
			</li>
			<li>
				<base-badge type="author" caption="AUTHOR"></base-badge>
			</li>
		</ul>
	</template>
</BaseCard>

# v-slot shorthand

<template #header> is equal to:

<template v-slot:header>

# Styling Slots

scope

the styling and the data ist not passed to the slot-component, still only available inside of the parent-component (the content is evaluated and styled before it is sent to the slot-component)

# slot default-content

you can provide default content, that is used if no content is sent to that slot

<header>
	<slot name="header">
		<h2>Default Content</h2>
	</slot>
</header>

# check, if slot gets data

this.$slots holds info about the slot data.this component receives

this.$slots.default accesses the default slot

-> you can check if slot receives data and only render it if it has data:

<header v-if="$slots.header">
	<slot name="header"> </slot>
</header>

# Scoped Slots

let you pass data from inside the component where you define the slot to the component, where you define the markup

<li v-for="goal in goals" :key="goal">
 <slot :item="goal" another-prop="some String"></slot>
</li>

the :item is available in the component where you pass data for the slot

   <CourseGoals>
      <template #default="slotProps">
        <h2>{{ slotProps.item }}</h2>
        <p>{{ slotProps.anotherProp }}</p>
  			<!-- <p>{{ slotProps['another-prop'] }}</p> -->
      </template>
    </CourseGoals>

"slotProps" is an Object, where all the props are merged in

if you are only using one slot, you can omit the <template>

<CourseGoals #default="slotProps">
	<h2>{{ slotProps.item }}</h2>
	<p>{{ slotProps.anotherProp }}</p>
</CourseGoals>